package com.jdd.modules.parkcar.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.andyczy.java.excel.ExcelUtils;
import com.jdd.common.api.vo.Result;
import com.jdd.common.aspect.annotation.*;
import com.jdd.common.constant.JddConstant;
import com.jdd.common.system.query.QueryGenerator;
import com.jdd.common.system.vo.LoginUser;
import com.jdd.common.util.BusinessUtils;
import com.jdd.common.util.LoginUserUtils;
import com.jdd.common.util.PlateNoCheckUtil;
import com.jdd.common.util.SnowFlakeUtil;
import com.jdd.common.util.excel.entity.params.ExportParams;
import com.jdd.common.util.excel.web.entity.vo.NormalExcelConstants;
import com.jdd.common.util.excel.web.view.EasypoiSingleExcelView;
import com.jdd.modules.configcartype.entity.ConfigCarType;
import com.jdd.modules.configcartype.service.IConfigCarTypeService;
import com.jdd.modules.parkcar.entity.ParkInnerForeverImport;
import com.jdd.modules.parkcar.entity.ParkInnerImport;
import com.jdd.modules.parkcar.entity.ParkInnerImportResult;
import com.jdd.modules.parkcar.entity.ParkInnerInfo;
import com.jdd.modules.parkcar.service.IParkInnerListService;
import com.jdd.modules.parkcar.util.ParkCarUtil;
import com.jdd.modules.parking.entity.ConfigParkInfo;
import com.jdd.modules.parking.entity.ParkCarEnterLog;
import com.jdd.modules.parking.service.IConfigParkInfoService;
import com.jdd.modules.parking.service.IparkCarEnterLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;


/**
 * @Description: 内部车辆管理
 * @author: ZhuLiuWei
 * @date: 2022/1/17 10:23
 */
@Slf4j
@Api(tags = "内部车辆")
@RestController
@RequestMapping("/innerList/parkInnerList")
public class ParkInnerListController {

    @Resource
    private IParkInnerListService parkInnerListService;
    @Resource
    private ExecutorService executorService;
    @Resource
    private IConfigParkInfoService configParkInfoService;
    @Resource
    private IparkCarEnterLogService parkCarEnterLogService;
    @Resource
    private IConfigCarTypeService configCarTypeService;

    /**
     * 内部车辆分页列表查询
     *
     * @param parkInnerInfo
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AutoLog(value = "内部车辆-分页列表查询")
    @ApiOperation(value = "内部车辆-分页列表查询", notes = "内部车辆-分页列表查询")
    @GetMapping(value = "/list")
    public Result<IPage<ParkInnerInfo>> queryPageList(ParkInnerInfo parkInnerInfo,
                                                      @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                      @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                      HttpServletRequest req) {
        Result<IPage<ParkInnerInfo>> result = new Result<>();
        QueryWrapper<ParkInnerInfo> queryWrapper = new QueryWrapper<>();
        String startTime = req.getParameter("endTime_begin");
        String endTime = req.getParameter("endTime_end");
        if (ObjectUtil.isNotEmpty(parkInnerInfo.getIsForever())) {
            queryWrapper.eq("is_forever", parkInnerInfo.getIsForever());
        }
        if (ObjectUtil.isNotEmpty(parkInnerInfo.getPlateNo())) {
            queryWrapper.like("plate_no", parkInnerInfo.getPlateNo());
        }
        //时间用大于小于
        if (ObjectUtil.isNotNull(startTime)) {
            queryWrapper.ge("start_time", startTime);
        }
        if (ObjectUtil.isNotNull(endTime)) {
            queryWrapper.le("end_time", endTime);
        }
        if (ObjectUtil.isNotEmpty(parkInnerInfo.getUserName())) {
            queryWrapper.like("user_name", parkInnerInfo.getUserName());
        }
        if (ObjectUtil.isNotEmpty(parkInnerInfo.getMobile())) {
            queryWrapper.like("mobile", parkInnerInfo.getMobile());
        }
        queryWrapper.orderByDesc("create_time");

        Page<ParkInnerInfo> page = new Page<>(pageNo, pageSize);
        IPage<ParkInnerInfo> pageList = parkInnerListService.page(page, queryWrapper);
        result.setSuccess(true);
        result.setResult(pageList);
        return result;
    }

    /**
     * 内部车辆添加
     *
     * @param parkInnerInfo
     * @return
     */
    @AutoLog(value = "内部车辆-添加")
    @ApiOperation(value = "内部车辆-添加", notes = "内部车辆-添加")
    @PostMapping(value = "/add")
    @OperationLogDetail(detail = "内部车辆添加", level = LogLevelType.ONE, operationType = OperationType.INSERT, operationUnit = OperationUnit.UNKNOWN)
    public Result<ParkInnerInfo> add(@RequestBody ParkInnerInfo parkInnerInfo) {
        ConfigParkInfo configParkInfo = configParkInfoService.findConfigParkInfoByParkCode();
        if (ObjectUtil.isNull(configParkInfo)) {
            return Result.error("车辆信息配置为空，请检查");
        }
        parkInnerInfo.setParkCode(configParkInfo.getParkCode());
        parkInnerInfo.setParkName(configParkInfo.getParkName());
        parkInnerInfo.setId(SnowFlakeUtil.getId());
        parkInnerInfo.setCreateUser(LoginUserUtils.getLoginUser().getUsername());
        LambdaQueryWrapper<ParkInnerInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParkInnerInfo::getPlateNo, parkInnerInfo.getPlateNo());

        if (CollectionUtil.isNotEmpty(parkInnerListService.list(queryWrapper))) {
            return Result.error("该车牌号已添加过内部车辆，请勿重复添加");
        }

        boolean ok = parkInnerListService.save(parkInnerInfo);
        if (ok) {
            if (JddConstant.StringNumber.STRING_ONE.equals(parkInnerInfo.getIsForever())) {
                ParkCarEnterLog lastCarEnterLog = parkCarEnterLogService.getLastCarEnterLog(configParkInfo.getParkCode(), parkInnerInfo.getPlateNo(), JddConstant.ParkCarEnterLog.CAR_NO_OUT);
                //如果新增车辆为场内车辆且为临时车则新入一条入场记录
                if (lastCarEnterLog != null && JddConstant.StringNumber.STRING_ZERO.equals(lastCarEnterLog.getCarNature())) {
                    //拷贝属性
                    ParkCarEnterLog newParkCarEnterLog = new ParkCarEnterLog();
                    BeanUtils.copyProperties(lastCarEnterLog, newParkCarEnterLog);
                    LocalDateTime parse = LocalDateTime.parse(lastCarEnterLog.getCarEnterTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    LocalDateTime localDateTime = parse.plusSeconds(1L);
                    String newCarEnterTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    newParkCarEnterLog.setId(SnowFlakeUtil.getId());
                    newParkCarEnterLog.setCarEnterTime(newCarEnterTime);
                    newParkCarEnterLog.setCarTypeNo(String.valueOf(JddConstant.TemporaryCarType.TEMPORARY_CAR_INNER));
                    ConfigCarType configCarType = this.getCarType(newParkCarEnterLog.getParkCode(), Integer.valueOf(newParkCarEnterLog.getCarTypeNo()));
                    if (null != configCarType) {
                        newParkCarEnterLog.setCarTypeId(configCarType.getId());
                        newParkCarEnterLog.setCarTypeName(configCarType.getCarTypeName());
                    }
                    newParkCarEnterLog.setRemark("新增内部车辆，重新录入入场记录");
                    newParkCarEnterLog.setUpdateTime(new Date());
                    parkCarEnterLogService.save(newParkCarEnterLog);

                    lastCarEnterLog.setIsOut(JddConstant.StringNumber.STRING_ONE);
                    parkCarEnterLogService.updateById(lastCarEnterLog);
                }
            }
            return Result.ok("添加成功");
        }
        return Result.error("添加失败");
    }

    /**
     * 内部车辆编辑
     *
     * @param parkInnerInfo
     * @return
     */
    @AutoLog(value = "内部车辆-编辑")
    @ApiOperation(value = "内部车辆-编辑", notes = "内部车辆-编辑")
    @PutMapping(value = "/edit")
    @OperationLogDetail(detail = "内部车辆编辑", level = LogLevelType.ONE, operationType = OperationType.UPDATE, operationUnit = OperationUnit.UNKNOWN)
    public Result<?> edit(@RequestBody ParkInnerInfo parkInnerInfo) {
        ParkInnerInfo parkInnerInfoEntity = parkInnerListService.getById(parkInnerInfo.getId());
        if (parkInnerInfoEntity == null) {
            return Result.error("该内部车辆信息不存在");
        }

        LambdaQueryWrapper<ParkInnerInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParkInnerInfo::getPlateNo, parkInnerInfo.getPlateNo());
        queryWrapper.ne(ParkInnerInfo::getId, parkInnerInfo.getId());
        if (CollectionUtil.isNotEmpty(parkInnerListService.list(queryWrapper))) {
            return Result.error("该车牌号已添加过内部车辆，请勿重复添加");
        }

        UpdateWrapper<ParkInnerInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", parkInnerInfo.getId());
        updateWrapper.set("start_time", parkInnerInfo.getStartTime());
        updateWrapper.set("end_time", parkInnerInfo.getEndTime());
        updateWrapper.set("plate_no", parkInnerInfo.getPlateNo());
        updateWrapper.set("is_forever", parkInnerInfo.getIsForever());
        updateWrapper.set("user_name", parkInnerInfo.getUserName());
        updateWrapper.set("mobile", parkInnerInfo.getMobile());
        updateWrapper.set("address", parkInnerInfo.getAddress());
        updateWrapper.set("remark", parkInnerInfo.getRemark());
        updateWrapper.set("update_time", new Date());
        boolean ok = parkInnerListService.update(updateWrapper);
        if (ok) {
            if (JddConstant.StringNumber.STRING_ONE.equals(parkInnerInfo.getIsForever())) {
                ParkCarEnterLog lastCarEnterLog = parkCarEnterLogService.getLastCarEnterLog(parkInnerInfoEntity.getParkCode(), parkInnerInfo.getPlateNo(), JddConstant.ParkCarEnterLog.CAR_NO_OUT);
                //如果修改车辆为场内车辆且为临时车则新入一条入场记录
                if (lastCarEnterLog != null && JddConstant.StringNumber.STRING_ZERO.equals(lastCarEnterLog.getCarNature())) {
                    //拷贝属性
                    ParkCarEnterLog newParkCarEnterLog = new ParkCarEnterLog();
                    BeanUtils.copyProperties(lastCarEnterLog, newParkCarEnterLog);
                    LocalDateTime parse = LocalDateTime.parse(lastCarEnterLog.getCarEnterTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    LocalDateTime localDateTime = parse.plusSeconds(1L);
                    String newCarEnterTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    newParkCarEnterLog.setId(SnowFlakeUtil.getId());
                    newParkCarEnterLog.setCarEnterTime(newCarEnterTime);
                    newParkCarEnterLog.setCarTypeNo(String.valueOf(JddConstant.TemporaryCarType.TEMPORARY_CAR_INNER));
                    ConfigCarType configCarType = this.getCarType(newParkCarEnterLog.getParkCode(), Integer.valueOf(newParkCarEnterLog.getCarTypeNo()));
                    if (null != configCarType) {
                        newParkCarEnterLog.setCarTypeId(configCarType.getId());
                        newParkCarEnterLog.setCarTypeName(configCarType.getCarTypeName());
                    }
                    newParkCarEnterLog.setRemark("修改内部车辆，重新录入入场记录");
                    newParkCarEnterLog.setUpdateTime(new Date());
                    parkCarEnterLogService.save(newParkCarEnterLog);

                    lastCarEnterLog.setIsOut(JddConstant.StringNumber.STRING_ONE);
                    parkCarEnterLogService.updateById(lastCarEnterLog);
                }
            }
            return Result.ok();
        }
        return Result.error("编辑失败");
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "内部车辆-通过id删除")
    @ApiOperation(value = "内部车辆-通过id删除", notes = "内部车辆-通过id删除")
    @DeleteMapping(value = "/delete")
    @OperationLogDetail(detail = "内部车辆通过id删除", level = LogLevelType.ONE, operationType = OperationType.DELETE, operationUnit = OperationUnit.UNKNOWN)
    public Result<?> delete(@RequestParam(name = "id") String id) {
        try {
            parkInnerListService.removeById(id);
        } catch (Exception e) {
            log.error("删除失败", e.getMessage());
            return Result.error("删除失败!");
        }
        return Result.ok("删除成功!");
    }

    /**
     * 内部车辆批量删除
     *
     * @param ids
     * @return
     */
    @AutoLog(value = "内部车辆-批量删除")
    @ApiOperation(value = "内部车辆-批量删除", notes = "内部车辆-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    @OperationLogDetail(detail = "内部车辆批量删除", level = LogLevelType.ONE, operationType = OperationType.DELETE, operationUnit = OperationUnit.UNKNOWN)
    public Result<ParkInnerInfo> deleteBatch(@RequestParam(name = "ids") String ids) {
        Result<ParkInnerInfo> result = new Result<>();
        if (ids == null || "".equals(ids.trim())) {
            result.error500("参数不识别！");
        } else {
            this.parkInnerListService.removeByIds(Arrays.asList(ids.split(",")));
            result.success("删除成功!");
        }
        return result;
    }

    /**
     * 导出excel
     *
     * @param request
     * @param response
     */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response, ParkInnerInfo parkInnerInfo) throws ExecutionException, InterruptedException {
        //组装查询条件
        QueryWrapper<ParkInnerInfo> queryWrapper = QueryGenerator.initQueryWrapper(parkInnerInfo, request.getParameterMap());
        queryWrapper.orderByDesc("create_time");
        ParkCarUtil parkCarUtil = new ParkCarUtil();
        //AutoPoi 导出Excel
        ModelAndView mv = new ModelAndView(new EasypoiSingleExcelView());
        mv.addObject(NormalExcelConstants.FILE_NAME, "内部车辆列表");
        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("内部车辆列表数据", "导出信息"));
        // 导出文件名称
        ConfigParkInfo configParkInfo = configParkInfoService.findConfigParkInfoByParkCode();
        if (ObjectUtil.isNotNull(configParkInfo)) {
            // 查询表中数据大小
            int listSize = parkInnerListService.count(queryWrapper);
            // 定义每页数量
            int pageSize = 100;
            // 定义线程列表
            List<CompletableFuture<ModelAndView>> futureList = new ArrayList<>();
            // 循环查询，每次查询一页
            for (int pageNo = 1; pageNo <= listSize / pageSize + 1; pageNo++) {
                int number = pageNo;
                // 开启线程查询
                CompletableFuture<ModelAndView> completableFuture = CompletableFuture.supplyAsync(() -> parkCarUtil.addDataToModelAndViewInnerCar(new ModelAndView(), parkInnerListService, queryWrapper, number, pageSize), executorService);
                futureList.add(completableFuture);
            }
            // 等待每个线程结束后
            CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
            List<ParkInnerInfo> resultList = new ArrayList<>();
            futureList.forEach(a -> {
                try {
                    // 将结果添加到列表中
                    resultList.addAll((List<ParkInnerInfo>) a.join().getModel().get(NormalExcelConstants.DATA_LIST));
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            });
            // 将数据添加到Excel文件内
            mv.addObject(NormalExcelConstants.CLASS, ParkInnerInfo.class);
            mv.addObject(NormalExcelConstants.DATA_LIST, resultList);
        } else {
            mv.addObject(NormalExcelConstants.CLASS, String.class);
            mv.addObject(NormalExcelConstants.DATA_LIST, "请使用车场管理员账号进行操作");
        }
        return mv;
    }

    /**
     * 获取车场配置信息
     *
     * @return 车场配置信息
     */
    @AutoLog(value = "内部车辆信息导入-获取车场配置信息")
    @ApiOperation(value = "内部车辆信息导入-获取车场配置信息", notes = "内部车辆信息导入-获取车场配置信息")
    @GetMapping(value = "/findConfigParkInfo")
    public Result<?> findConfigParkInfo(HttpServletRequest request) {
        request.getSession();
        ConfigParkInfo configParkInfo = configParkInfoService.findConfigParkInfoByParkCode();
        if (ObjectUtil.isNull(configParkInfo)) {
            return Result.error("获取车场配置信息失败！");
        } else {
            return Result.ok(configParkInfo);
        }
    }

    /**
     * 内部车辆信息导入模板下载
     *
     * @param request   request
     * @param response  response
     * @param isForever 有效期 1：永久期限 0： 自定义时间
     * @return 模板信息
     */
    @AutoLog(value = "内部车辆信息导入模板下载")
    @ApiOperation(value = "内部车辆信息导入模板下载", notes = "内部车辆信息导入模板下载")
    @RequestMapping(value = "/importTemplate")
    public ModelAndView importTemplate(HttpServletRequest request, HttpServletResponse response, String isForever) {
        ModelAndView mv = new ModelAndView(new EasypoiSingleExcelView());

        if (JddConstant.StringNumber.STRING_ONE.equals(isForever)) {
            //永久期限模板
            List<ParkInnerForeverImport> list = new LinkedList<>();
            ParkInnerForeverImport parkInner = new ParkInnerForeverImport();

            mv.addObject(NormalExcelConstants.FILE_NAME, "内部车辆信息");
            mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("内部车辆信息", "内部车辆导入模板"));
            mv.addObject(NormalExcelConstants.CLASS, ParkInnerForeverImport.class);

            parkInner.setPlateNo("实际车牌号");
            parkInner.setIsForever("永久");
            parkInner.setUserName("XX");
            parkInner.setRemark("此行为示例数据,请参考格式填写，导入前请删除本行数据！");

            list.add(parkInner);
            mv.addObject(NormalExcelConstants.DATA_LIST, list);
        } else {
            //自定义时间模板
            List<ParkInnerImport> list = new LinkedList<>();
            ParkInnerImport parkInner = new ParkInnerImport();

            mv.addObject(NormalExcelConstants.FILE_NAME, "内部车辆信息(自定义时间)");
            mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("内部车辆信息(自定义时间)", "内部车辆信息模板(自定义时间)"));
            mv.addObject(NormalExcelConstants.CLASS, ParkInnerImport.class);

            parkInner.setPlateNo("实际车牌号");
            parkInner.setIsForever("自定义");
            parkInner.setStartTime("2022-12-01 08:00:00");
            parkInner.setEndTime("2022-12-31 18:00:00");
            parkInner.setUserName("XX");
            parkInner.setRemark("此行为示例数据,请参考格式填写，导入前请删除本行数据！");

            list.add(parkInner);
            mv.addObject(NormalExcelConstants.DATA_LIST, list);
        }
        return mv;
    }

    /**
     * 内部车辆校验及导入进度获取
     *
     * @param request  request
     * @param response response
     * @return 进度数据
     */
    @RequestMapping(value = "/getCheckProgress", method = RequestMethod.POST)
    public Result<Integer> getCheckProgress(HttpServletRequest request, HttpServletResponse response) {
        Result<Integer> result = new Result<>();
        String currDateTime = request.getParameter("currDateTime");
        try {
            String percent = String.valueOf(request.getSession().getAttribute(currDateTime));
            if (StringUtils.isEmpty(percent) || "null".equals(percent)) {
                percent = "0";
            }
            result.setResult(Integer.parseInt(percent));
        } catch (Exception e) {
            result.setResult(0);
        }
        return result;
    }

    /**
     * 内部车辆信息通过excel导入数据校验
     *
     * @param request  request
     * @param response response
     * @return 数据校验结果
     */
    @RequestMapping(value = "/importFromExcelCheck", method = RequestMethod.POST)
    public Result<List<ParkInnerImportResult>> importFromExcelCheck(HttpServletRequest request, HttpServletResponse response) throws IOException {

        Result<List<ParkInnerImportResult>> result = new Result<>();
        //校验结果信息列表
        List<ParkInnerImportResult> importResultMessageList = new LinkedList<>();
        //用于存储的格式正确的内部车辆信息
        List<ParkInnerInfo> parkInnerList = new ArrayList<>();
        //用于存储拥有相同数据的内部车辆信息
        List<ParkInnerInfo> sameParkInnerList = new ArrayList<>();

        // 获得上传文件的请求
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        //有效期 1：永久期限 0： 自定义时间
        String isForever = multipartRequest.getParameter("isForever");

        // 从请求中获得上传文件的集合
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        // 遍历文件集合
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            try {
                // 获得文件
                MultipartFile file = entity.getValue();
                // 得到文件名
                String fileName = file.getOriginalFilename();
                //得到文件扩展名
                String extName = fileName.substring(fileName.lastIndexOf('.') + 1);
                //excel文件格式校验
                if (!StringUtils.equals("xls", extName) && !StringUtils.equals("xlsx", extName)) {
                    log.error("无法识别的Excel文件,请下载模板文件,进行导入!");
                    result.error500("无法识别的Excel文件,请下载模板文件,进行导入");
                    return result;
                }

                //获取Excel数据
                List<List<LinkedHashMap<String, String>>> excelLists = getExcelLists(file, extName);
                //检测导入Excel文件的大小
                Result<Object> listSizeCheckResult = importListSizeCheck(excelLists, 500);
                //如果检测不通过
                if (listSizeCheckResult.getCode() != 200) {
                    result.error500(listSizeCheckResult.getMessage());
                    return result;
                }

                for (List<LinkedHashMap<String, String>> linkedHashMaps : excelLists) {
                    importResultMessageList = getNoSameDataParkCarInner(request, linkedHashMaps, parkInnerList, sameParkInnerList, isForever, true);
                }

                //文件数据校验失败
                if (importResultMessageList.size() > 0) {
                    result.setResult(importResultMessageList);
                    result.setSuccess(false);
                    return result;
                }
            } catch (Exception e) {
                log.error("内部车辆文件校验失败", e);
                result.error500("内部车辆文件校验失败");
                return result;
            }
        }

        result.success("内部车辆文件校验成功！");
        ParkInnerImportResult parkInnerImportResult = new ParkInnerImportResult();
        //校验总条数
        parkInnerImportResult.setTotalCount(parkInnerList.size());
        importResultMessageList.add(parkInnerImportResult);
        result.setResult(importResultMessageList);
        result.setSuccess(true);
        return result;
    }

    /**
     * 获取Excel数据
     *
     * @param file    文件
     * @param extName 文件扩展名
     * @return 列表数据
     * @throws IOException 异常信息
     */
    private List<List<LinkedHashMap<String, String>>> getExcelLists(MultipartFile file, String extName) throws IOException {
        // 设置Excel文件的标题所在行数
        HashMap<Integer, Integer> hashMapIndex = new HashMap<>(1);
        hashMapIndex.put(1, 3);
        // 设置Excel文件单页名称
        String[] sheetNames = new String[]{"内部车辆"};
        // 获得Excel文件的输入流
        InputStream inputStream = file.getInputStream();
        Workbook book = null;

        if (StringUtils.equals("xls", extName)) {
            book = new HSSFWorkbook(inputStream);
        } else if (StringUtils.equals("xlsx", extName)) {
            book = new XSSFWorkbook(inputStream);
        }

        ExcelUtils excelUtils = ExcelUtils.initialization();
        excelUtils.setDateFormatStr("yyyy-MM-dd HH:mm:ss");
        excelUtils.setExpectDateFormatStr("yyyy-MM-dd HH:mm:ss");
        // 读取Excel文件
        return ExcelUtils.importForExcelData(book, sheetNames, hashMapIndex, null);
    }

    /**
     * 内部车辆信息通过excel导入数据
     *
     * @param request  request
     * @param response response
     * @return 导入结果
     */
    @RequestMapping(value = "/importFromExcel", method = RequestMethod.POST)
    public Result<List<ParkInnerImportResult>> importFromExcel(HttpServletRequest request, HttpServletResponse response) {
        Result<List<ParkInnerImportResult>> result = new Result<>();
        //导入结果信息列表
        List<ParkInnerImportResult> importResultMessageList = new LinkedList<>();
        //用于存储的格式正确的内部车辆信息
        List<ParkInnerInfo> parkInnerList = new ArrayList<>();
        //用于存储拥有相同数据的内部车辆信息
        List<ParkInnerInfo> sameParkInnerList = new ArrayList<>();

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        //有效期 1：永久期限 0： 自定义时间
        String isForever = multipartRequest.getParameter("isForever");
        //导入方式 1:忽略重复(以已存在记录为准) 0:覆盖导入(以最新记录为准)
        String importType = multipartRequest.getParameter("importType");

        // 从请求中获得上传文件的集合
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        // 遍历文件集合
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            try {
                // 获得文件
                MultipartFile file = entity.getValue();
                // 得到文件名
                String fileName = file.getOriginalFilename();
                // 获得Excel文件的扩展名
                String extName = fileName.substring(fileName.lastIndexOf('.') + 1);
                //获取Excel数据
                List<List<LinkedHashMap<String, String>>> list = getExcelLists(file, extName);

                for (List<LinkedHashMap<String, String>> linkedHashMaps : list) {
                    getNoSameDataParkCarInner(request, linkedHashMaps, parkInnerList, sameParkInnerList, isForever, false);
                }

                importResultMessageList = importParkParkInnerByList(request, parkInnerList, importType);
                if (importResultMessageList.size() > 0) {
                    result.setResult(importResultMessageList);
                    result.setSuccess(false);
                    return result;
                }
            } catch (Exception e) {
                log.error("内部车辆导入失败", e);
                result.error500("内部车辆导入失败");
                return result;
            }
        }
        result.success("内部车辆导入成功！");
        ParkInnerImportResult parkInnerImportResult = new ParkInnerImportResult();
        parkInnerImportResult.setTotalCount(parkInnerList.size());
        importResultMessageList.add(parkInnerImportResult);
        result.setResult(importResultMessageList);
        result.setSuccess(true);
        return result;
    }

    /**
     * 检测内部车辆导入列表的大小
     *
     * @param list    导入数据列表
     * @param maxSize 最大数
     * @return 检测结果
     */
    private Result<Object> importListSizeCheck(List<List<LinkedHashMap<String, String>>> list, Integer maxSize) {

        // 如果列表大小不为0
        if (list.size() != 0) {
            if (list.get(0).size() > maxSize) {
                log.error("导入文件表格中的数据最大为" + maxSize + "条");
                return Result.error("导入文件表格中的数据最大为" + maxSize + "条");
            }
            if (list.get(0).size() != 0) {
                String[] arr = new String[list.get(0).get(0).size()];
                Arrays.fill(arr, "");
                String[] arr1 = new String[list.get(0).get(0).size()];
                String[] strings = list.get(0).get(0).values().toArray(arr1);
                if (Arrays.equals(arr, strings)) {
                    log.error("文件没有数据");
                    return Result.error("文件没有数据！");
                }
            } else {
                log.error("文件没有数据");
                return Result.error("文件没有数据！");
            }
        } else {
            log.error("空文件");
            return Result.error("空文件");
        }
        return Result.ok();
    }

    /**
     * 按list批量导入
     *
     * @param request    request
     * @param list       格式正确的储值车信息
     * @param importType 导入方式 1:忽略重复(以已存在记录为准) 0:覆盖导入(以最新记录为准)
     * @return 导入结果信息
     */
    private List<ParkInnerImportResult> importParkParkInnerByList(HttpServletRequest request, List<ParkInnerInfo> list, String importType) {
        List<ParkInnerImportResult> importResultMessageList = new ArrayList<>();
        String currDateTime = request.getParameter("currDateTime");
        for (int i = 0; i < list.size(); i++) {
            ParkInnerInfo parkInnerInfo = list.get(i);
            try {
                // 创建一个数值格式化对象
                NumberFormat numberFormat = NumberFormat.getInstance();
                numberFormat.setMaximumFractionDigits(0);
                String result = numberFormat.format((float) i / (float) list.size() * 100);
                request.getSession().setAttribute(currDateTime, Integer.parseInt(result));

                LambdaQueryWrapper<ParkInnerInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ParkInnerInfo::getPlateNo, parkInnerInfo.getPlateNo());
                ParkInnerInfo exitParkInnerInfo = parkInnerListService.getOne(queryWrapper);
                if (null != exitParkInnerInfo) {
                    //忽略重复(以已存在记录为准)
                    if (JddConstant.StringNumber.STRING_ONE.equals(importType)) {
                        continue;
                    } else {
                        //覆盖导入(以最新记录为准)
                        parkInnerListService.removeById(exitParkInnerInfo.getId());
                        parkInnerListService.save(parkInnerInfo);
                    }
                } else {
                    parkInnerListService.save(parkInnerInfo);
                }
            } catch (Exception e) {
                ParkInnerImportResult message = new ParkInnerImportResult();
                message.setTotalCount(list.size());
                message.setId(i + 3);
                message.setPlateNo(parkInnerInfo.getPlateNo());
                message.setUserName(parkInnerInfo.getUserName());
                message.setMessage("导入失败" + e.getMessage());
                message.setStatus("失败");
                importResultMessageList.add(message);
            }
        }
        return importResultMessageList;
    }

    /**
     * Excel列表中数据格式自检测
     *
     * @param request        request
     * @param linkedHashMaps 导入的内部车辆信息列表
     * @param noSameDataList 用于存储的格式正确的内部车辆信息
     * @param sameDatalist   用于存储拥有相同数据的内部车辆信息
     * @param isForever      有效期 1：永久期限 0： 自定义时间
     * @param isCheck        是否为校验操作
     * @return 导入结果信息
     */
    private List<ParkInnerImportResult> getNoSameDataParkCarInner(HttpServletRequest request, List<LinkedHashMap<String, String>> linkedHashMaps, List<ParkInnerInfo> noSameDataList,
                                                                  List<ParkInnerInfo> sameDatalist, String isForever, boolean isCheck) {
        LoginUser loginUser = LoginUserUtils.getLoginUser();
        List<ParkInnerImportResult> resultList = new ArrayList<>();
        Set<String> noSameDataPlantNoList = new HashSet<>();
        ConfigParkInfo configParkInfo = configParkInfoService.findConfigParkInfoByParkCode();
        String currDateTime = request.getParameter("currDateTime");

        for (int index = 0; index < linkedHashMaps.size(); index++) {
            //文件数据校验时设置进度数据
            if (isCheck) {
                // 创建一个数值格式化对象
                NumberFormat numberFormat = NumberFormat.getInstance();
                numberFormat.setMaximumFractionDigits(0);
                String result = numberFormat.format((float) index / (float) linkedHashMaps.size() * 100);
                request.getSession().setAttribute(currDateTime, Integer.parseInt(result));
            }
            ParkInnerInfo parkInnerInfo = new ParkInnerInfo();
            LinkedHashMap<String, String> linkedHashMap = linkedHashMaps.get(index);
            //车牌号
            String plateNo = linkedHashMap.get("0");
            //车主
            String userName;
            //手机号码
            String mobile;
            //地址
            String address;
            //备注信息
            String remark;
            //起始时间
            String startTime;
            //结束时间
            String endTime;

            ParkInnerImportResult message = new ParkInnerImportResult();
            message.setTotalCount(linkedHashMaps.size());
            message.setId(index + 3);
            message.setPlateNo(plateNo);
            message.setStatus("失败");

            if (StringUtils.isBlank(plateNo) || !PlateNoCheckUtil.checkPlateNo(plateNo)) {
                // 如果车辆的车牌号为空或错误的格式，放弃此数据，立即开始导入一下条数据
                log.error("车牌号格式错误");
                if (JddConstant.StringNumber.STRING_ONE.equals(isForever)) {
                    message.setUserName(linkedHashMap.get("2"));
                } else {
                    message.setUserName(linkedHashMap.get("4"));
                }
                message.setMessage("车牌号格式错误");
                resultList.add(message);
                continue;
            } else {
                parkInnerInfo.setPlateNo(plateNo);
            }
            //永久有效
            if (JddConstant.StringNumber.STRING_ONE.equals(isForever)) {
                userName = linkedHashMap.get("2");
                mobile = linkedHashMap.get("3");
                address = linkedHashMap.get("4");
                remark = linkedHashMap.get("5");
                message.setUserName(userName);
            } else {
                //自定义时间
                userName = linkedHashMap.get("4");
                mobile = linkedHashMap.get("5");
                address = linkedHashMap.get("6");
                remark = linkedHashMap.get("7");
                message.setUserName(userName);

                startTime = linkedHashMap.get("2");
                if (dateTimeCheck(startTime, "yyyy-MM-dd HH:mm:ss")) {
                    parkInnerInfo.setStartTime(startTime);
                } else {
                    log.error("有效期开始时间格式错误");
                    message.setMessage("有效期开始时间格式错误");
                    resultList.add(message);
                    continue;
                }
                endTime = linkedHashMap.get("3");
                if (dateTimeCheck(endTime, "yyyy-MM-dd HH:mm:ss")) {
                    parkInnerInfo.setEndTime(endTime);
                } else {
                    log.error("有效期结束时间格式错误");
                    message.setMessage("有效期结束时间格式错误");
                    resultList.add(message);
                    continue;
                }
            }

            if (StringUtils.isEmpty(userName) || userName.length() <= 40) {
                parkInnerInfo.setUserName(userName);
            } else {
                log.error("车主/姓名长度不要超过40个字符");
                message.setMessage("车主/姓名长度不要超过40个字符");
                resultList.add(message);
                continue;
            }

            if (StringUtils.isNotEmpty(mobile)) {
                if (BusinessUtils.checkMobile(mobile)) {
                    parkInnerInfo.setMobile(mobile);
                } else {
                    log.error("手机号码格式不正确");
                    message.setMessage("手机号码格式不正确");
                    resultList.add(message);
                    continue;
                }
            }

            if (StringUtils.isEmpty(address) || address.length() <= 100) {
                parkInnerInfo.setAddress(address);
            } else {
                log.error("家庭住址长度不要超过100个字符");
                message.setMessage("家庭住址长度不要超过100个字符");
                resultList.add(message);
                continue;
            }

            if (StringUtils.isEmpty(remark) || remark.length() <= 100) {
                parkInnerInfo.setRemark(remark);
            } else {
                log.error("车辆备注长度不要超过100个字符");
                message.setMessage("车辆备注长度不要超过100个字符");
                resultList.add(message);
                continue;
            }

            parkInnerInfo.setId(SnowFlakeUtil.getId());
            parkInnerInfo.setIsForever(isForever);
            parkInnerInfo.setParkCode(configParkInfo.getParkCode());
            parkInnerInfo.setParkName(configParkInfo.getParkName());
            parkInnerInfo.setStatus("Y");
            parkInnerInfo.setUpdateTime(new Date());
            parkInnerInfo.setCreateUser(loginUser.getUsername());

            if (noSameDataPlantNoList.add(parkInnerInfo.getPlateNo())) {
                noSameDataList.add(parkInnerInfo);
            } else {
                message.setMessage("导入文件中已存在一条相同车牌号的数据，请勿重复导入");
                resultList.add(message);
                sameDatalist.add(parkInnerInfo);
            }
        }
        return resultList;
    }

    /**
     * 校验时间格式
     *
     * @param inputDateTime 时间字符串
     * @param format        时间格式
     * @return 校验结果
     */
    private boolean dateTimeCheck(String inputDateTime, String format) {
        SimpleDateFormat sdfDay = new SimpleDateFormat(format);
        sdfDay.setLenient(false);
        if (StringUtils.isEmpty(inputDateTime)) {
            return false;
        }
        try {
            Date date = sdfDay.parse(inputDateTime);
            return inputDateTime.equals(sdfDay.format(date));
        } catch (ParseException e) {
            return false;
        }
    }

    /**
     * 获取识别类型对应的车辆类型
     */
    public ConfigCarType getCarType(String parkCode, int type) {
        QueryWrapper<ConfigCarType> configCarTypeQueryWrapper = new QueryWrapper<>();
        configCarTypeQueryWrapper.eq("park_code", parkCode);
        List<ConfigCarType> configCarTypeList = configCarTypeService.list(configCarTypeQueryWrapper);
        for (ConfigCarType configCarType : configCarTypeList) {
            configCarType.getCarTypeNo();
            List<String> list = Arrays.asList(configCarType.getCarTypeNo().split(","));
            if (list.contains(String.valueOf(type))) {
                return configCarType;
            }
        }
        return null;
    }

}
